package ljt.floatball.widget;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.graphics.drawable.AnimationDrawable;
import android.support.annotation.LayoutRes;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;

import java.util.Observable;
import java.util.Observer;

import ljt.floatball.R;
import ljt.floatball.utils.PixelUtils;

/**
 * @author jiangtao
 */
public class FloatingDragger implements Observer {
  private PositionObservable observable = PositionObservable.getInstance();
  private FloatingDraggedView floatingDraggedView;
  private Context context;
  //半径
  private int radius = PixelUtils.dp2px(100f);
  //中心圆的长宽
  private int centerImageRadius;
  private boolean isMenuShow = false;
  private View floatingView;
  private View view1;
  private View view2;
  private View view3;
  private View view4;
  //  private View view5;
//  private View view6;
//  private View view7;
//  private View view8;
  private int itemNum = 4;

  public FloatingDragger(Context context, @LayoutRes int layoutResID) {
    this.context = context;
    centerImageRadius = dip2px(context, 80);
    // 用户布局
    View contentView = LayoutInflater.from(context).inflate(layoutResID, null);
    // 悬浮球按钮
    floatingView = LayoutInflater.from(context).inflate(R.layout.layout_floating_dragged, null);

    // ViewDragHelper的ViewGroup容器
    floatingDraggedView = new FloatingDraggedView(context);
    floatingDraggedView.addView(contentView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    floatingDraggedView.addView(floatingView, new FrameLayout.LayoutParams(centerImageRadius, centerImageRadius));

    floatingDraggedView.postDelayed(floatingDraggedView.mFadeOutRunnable, 3000);

    view1 = LayoutInflater.from(context).inflate(R.layout.float_btn, null);
    view2 = LayoutInflater.from(context).inflate(R.layout.float_btn, null);
    view3 = LayoutInflater.from(context).inflate(R.layout.float_btn, null);
    view4 = LayoutInflater.from(context).inflate(R.layout.float_btn, null);

//    view5 = LayoutInflater.from(context).inflate(R.layout.name_tag, null);
//    view6 = LayoutInflater.from(context).inflate(R.layout.name_tag, null);
//    view7 = LayoutInflater.from(context).inflate(R.layout.name_tag, null);
//    view8 = LayoutInflater.from(context).inflate(R.layout.name_tag, null);

    ((ImageView) view1.findViewById(R.id.menu_item_img)).setImageResource(R.mipmap.icon_float_order);
    ((ImageView) view2.findViewById(R.id.menu_item_img)).setImageResource(R.mipmap.icon_float_edit);
    ((ImageView) view3.findViewById(R.id.menu_item_img)).setImageResource(R.mipmap.icon_float_letter);
    ((ImageView) view4.findViewById(R.id.menu_item_img)).setImageResource(R.mipmap.icon_float_position);

//    ((ImageView) view5.findViewById(R.id.name_tag)).setImageResource(R.mipmap.icon_float_order_name);
//    ((ImageView) view6.findViewById(R.id.name_tag)).setImageResource(R.mipmap.icon_float_edit_name);
//    ((ImageView) view7.findViewById(R.id.name_tag)).setImageResource(R.mipmap.icon_float_letter_name);
//    ((ImageView) view8.findViewById(R.id.name_tag)).setImageResource(R.mipmap.icon_float_position_name);

    // 添加观察者
    observable.addObserver(this);
  }

  //隐藏悬浮窗
  public void dismissFloat() {
    floatingDraggedView.removeView(view1);
    floatingDraggedView.removeView(view2);
    floatingDraggedView.removeView(view3);
    floatingDraggedView.removeView(view4);
//    floatingDraggedView.removeView(view5);
//    floatingDraggedView.removeView(view6);
//    floatingDraggedView.removeView(view7);
//    floatingDraggedView.removeView(view8);
    floatingDraggedView.removeView(floatingView);
  }

  //显示悬浮窗
  public void showFloat() {
    boolean shown = floatingView.isShown();
    if (!shown) {
      dismissFloat();
      floatingDraggedView.setFloatImage(R.drawable.float_btn);
      floatingDraggedView.addView(floatingView, new FrameLayout.LayoutParams(centerImageRadius, centerImageRadius));
      floatingDraggedView.postDelayed(floatingDraggedView.mFadeOutRunnable, 3000);
    }
  }

  /**
   * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
   */
  public static int dip2px(Context context, float dpValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
  }

  /**
   * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
   */
  public static int px2dip(Context context, float pxValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (pxValue / scale + 0.5f);
  }

  public View getView() {
    return floatingDraggedView;
  }

  @Override
  public void update(Observable o, Object arg) {
    if (floatingDraggedView != null) {
      // 更新位置
      floatingDraggedView.restorePosition();
    }
  }

  public class FloatingDraggedView extends FrameLayout {
    private float mLastX;
    private float mLastY;
    ViewDragHelper dragHelper;
    SharedPreferences sp = getContext().getSharedPreferences("FloatingDraggedView", Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sp.edit();
    ImageView floatImageView;
    //靠右时左移距离
    private int moveLeftOnTheRight = 100;

    public FloatingDraggedView(Context context) {
      super(context);
      init();
    }

    public FloatingDraggedView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init();
    }

    public FloatingDraggedView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
      super.onLayout(changed, left, top, right, bottom);
      restorePosition();
    }

    void init() {
      dragHelper = ViewDragHelper.create(FloatingDraggedView.this, 1.0f, new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
          Log("tryCaptureView:" + child + "," + pointerId);
          closeMenu();
          return child == floatImageView;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
          Log("clampViewPositionVertical:" + child + "," + top + "," + dy);
          if (top > getHeight() - child.getMeasuredHeight()) {
            top = getHeight() - child.getMeasuredHeight();
          } else if (top < 0) {
            top = 0;
          }
          return top;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
          Log("clampViewPositionHorizontal:" + child + "," + left + dx);
          if (left > getWidth() - child.getMeasuredWidth()) {
            left = getWidth() - child.getMeasuredWidth();
          } else if (left < 0) {
            left = 0;
          }
          return left;
        }

        @Override
        public int getViewVerticalDragRange(View child) {
          Log("getViewVerticalDragRange:" + child);
          return getMeasuredHeight() - child.getMeasuredHeight();
        }

        @Override
        public int getViewHorizontalDragRange(View child) {
          Log("getViewHorizontalDragRange:" + child);
          return getMeasuredWidth() - child.getMeasuredWidth();
        }

        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
          Log("onViewPositionChanged:" + changedView + "," + left + "," + top + "," + dx + "," + dy);
          super.onViewPositionChanged(changedView, left, top, dx, dy);
          savePosition();
        }

        @Override
        public void onViewDragStateChanged(int state) {
          Log("onViewDragStateChanged:" + state);
          super.onViewDragStateChanged(state);
          closeMenuQuick();
          if (state == ViewDragHelper.STATE_SETTLING) { // 拖拽结束，通知观察者
            observable.update();
          }
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
          Log("onViewReleased:" + releasedChild + "," + xvel + "," + yvel);
          super.onViewReleased(releasedChild, xvel, yvel);
          if (releasedChild == floatImageView) {
            float x = floatImageView.getX();
            float y = floatImageView.getY();
            if (x < (getMeasuredWidth() / 2f - releasedChild.getMeasuredWidth() / 2f)) { // 0-x/2
              x = 0;
//                            if (x < releasedChild.getMeasuredWidth() / 3f) {
//                                x = 0;
//                            }
              if (y < (releasedChild.getMeasuredHeight() * 2)) { // 0-y/3
                y = PixelUtils.dp2px(120f);
              } else if (y > (getMeasuredHeight() - releasedChild.getMeasuredHeight() * 2)) { // 0-(y-y/3)
                y = getMeasuredHeight() - releasedChild.getMeasuredHeight() - PixelUtils.dp2px(100f);
              }
            } else { // x/2-x
              x = getMeasuredWidth() - releasedChild.getMeasuredWidth();
//                            if (x > getMeasuredWidth() - releasedChild.getMeasuredWidth() / 3f - releasedChild.getMeasuredWidth()) {
//                                x = getMeasuredWidth() - releasedChild.getMeasuredWidth();
//                            }
              if (y < (releasedChild.getMeasuredHeight() * 2)) { // 0-y/3
                y = PixelUtils.dp2px(120f);
              } else if (y > (getMeasuredHeight() - releasedChild.getMeasuredHeight() * 2)) { // 0-(y-y/3)
                y = getMeasuredHeight() - releasedChild.getMeasuredHeight() - PixelUtils.dp2px(100f);
              }
            }
            // 移动到指定位置
            dragHelper.smoothSlideViewTo(releasedChild, (int) x, (int) y);
            invalidate();
            postDelayed(mFadeOutRunnable, 3000);
          }
        }

        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
          Log("onViewCaptured:" + capturedChild + "," + activePointerId);
          super.onViewCaptured(capturedChild, activePointerId);
        }

        @Override
        public void onEdgeTouched(int edgeFlags, int pointerId) {
          Log("onEdgeTouched:" + edgeFlags + "," + pointerId);
          super.onEdgeTouched(edgeFlags, pointerId);
        }

        @Override
        public boolean onEdgeLock(int edgeFlags) {
          Log("onEdgeLock:" + edgeFlags);
          return super.onEdgeLock(edgeFlags);
        }

        @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
          Log("onEdgeDragStarted:" + edgeFlags + "," + pointerId);
          super.onEdgeDragStarted(edgeFlags, pointerId);
        }

        @Override
        public int getOrderedChildIndex(int index) {
          Log("getOrderedChildIndex:" + index);
          return super.getOrderedChildIndex(index);
        }
      });
    }

    public static final String KEY_FLOATING_X = "KEY_FLOATING_X";
    public static final String KEY_FLOATING_Y = "KEY_FLOATING_Y";

    @Override
    protected void onDetachedFromWindow() {
      super.onDetachedFromWindow();
      savePosition();
      observable.deleteObserver(FloatingDragger.this);
    }

    /**
     * 保存位置
     */
    void savePosition() {
      float x = floatImageView.getX();
      float y = floatImageView.getY();

      editor.putFloat(KEY_FLOATING_X, x);
      editor.putFloat(KEY_FLOATING_Y, y);
      editor.commit();
    }

    @Override
    protected void onAttachedToWindow() {
      Log("onAttachedToWindow");
      super.onAttachedToWindow();
      floatImageView = findViewById(R.id.float_img);
      AnimationDrawable animationDrawable = (AnimationDrawable) floatImageView.getDrawable();
      animationDrawable.start();
      floatImageView.setOnClickListener(v -> showMenuDialog());
    }

    /**
     * 显示菜单
     */
    long lastClickTime = System.currentTimeMillis();

    public void showMenuDialog() {
      if (System.currentTimeMillis() - lastClickTime > 600) {
        lastClickTime = System.currentTimeMillis();
        if (!isMenuShow) {
          showMenu();
        } else {
          closeMenu();
        }
      }
    }

    private void closeMenuQuick() {
      isMenuShow = false;
      floatingDraggedView.removeView(view1);
      floatingDraggedView.removeView(view2);
      floatingDraggedView.removeView(view3);
      floatingDraggedView.removeView(view4);
//      floatingDraggedView.removeView(view5);
//      floatingDraggedView.removeView(view6);
//      floatingDraggedView.removeView(view7);
//      floatingDraggedView.removeView(view8);
    }

    private void closeMenu() {
      lastClickTime = System.currentTimeMillis() + 100;
      removeCallbacks(closeRunnable);
      postDelayed(mFadeOutRunnable, 3000);
      isMenuShow = false;
      for (int i = 1; i <= itemNum; i++) {

        float x = floatImageView.getX();
        float y = floatImageView.getY();

        int width = floatingDraggedView.getWidth();
        int height = floatingDraggedView.getHeight();


        float degrees;
        int halfWidth = width / 2;
        if (x < halfWidth) {
          degrees = 45 * i - 22.5f;
        } else {
          degrees = 360 - (45 * i - 22.5f);
        }

        double angel = Math.PI * degrees / 180;

        float toX = (float) Math.sin(angel) * radius * 3f / 4f;
        float toY = (float) Math.cos(angel) * radius;

        //拖动窗与悬浮窗中心对齐需要移动的距离
        int correctDistance = (centerImageRadius - dip2px(context, 60)) / 2;
        //正确的点
        float rightX = x + correctDistance;
        float rightY = y + correctDistance;

        View floatView;
//        View nameTagView;
        long delayTime;
        if (i == 1) {
          delayTime = 0;
          floatView = view1;
//          nameTagView = view5;
        } else if (i == 2) {
          delayTime = 200;
          floatView = view2;
//          nameTagView = view6;
        } else if (i == 3) {
          delayTime = 300;
          floatView = view3;
//          nameTagView = view7;
        } else {
          delayTime = 100;
          floatView = view4;
//          nameTagView = view8;
        }

        Log("toX:" + toX);
        Log("toY:" + toY);

        AnimatorSet set = new AnimatorSet();

        ObjectAnimator animatorX = ObjectAnimator.ofFloat(floatView, "X", rightX + toX, rightX);
        animatorX.setInterpolator(new AnticipateInterpolator());
        animatorX.setDuration(300);

        ObjectAnimator animatorY = ObjectAnimator.ofFloat(floatView, "Y", rightY + toY, rightY);
        animatorY.setInterpolator(new AnticipateInterpolator());
        animatorY.setDuration(300);

//        ObjectAnimator animatorName = ObjectAnimator.ofFloat(nameTagView, "alpha", 1, 0);
//        animatorName.setDuration(300);

        set.setStartDelay(delayTime);
        set.play(animatorX).with(animatorY)/*.with(animatorName)*/;
        set.start();
        set.addListener(new Animator.AnimatorListener() {
          @Override
          public void onAnimationStart(Animator animation) {

          }

          @Override
          public void onAnimationEnd(Animator animation) {
            floatingDraggedView.removeView(floatView);
//            floatingDraggedView.removeView(nameTagView);
          }

          @Override
          public void onAnimationCancel(Animator animation) {

          }

          @Override
          public void onAnimationRepeat(Animator animation) {

          }
        });
      }
    }

    private void showMenu() {
      setFloatImage(R.drawable.float_btn);
      removeCallbacks(mFadeOutRunnable);
      isMenuShow = true;
      floatingDraggedView.removeView(view1);
      floatingDraggedView.removeView(view2);
      floatingDraggedView.removeView(view3);
      floatingDraggedView.removeView(view4);
//      floatingDraggedView.removeView(view5);
//      floatingDraggedView.removeView(view6);
//      floatingDraggedView.removeView(view7);
//      floatingDraggedView.removeView(view8);
      for (int i = 1; i <= itemNum; i++) {

        float x = floatImageView.getX();
        float y = floatImageView.getY();

        int width = floatingDraggedView.getWidth();
        int height = floatingDraggedView.getHeight();

        float degrees;
        int halfWidth = width / 2;
        if (x < halfWidth) {
          degrees = 45 * i - 22.5f;
        } else {
          degrees = 360 - (45 * i - 22.5f);
        }

        double angel = Math.PI * degrees / 180;

        float toX = (float) Math.sin(angel) * radius * 3f / 4f;
        float toY = (float) Math.cos(angel) * radius;

        //拖动窗与悬浮窗中心对齐需要移动的距离
        int correctDistance = (centerImageRadius - dip2px(context, 60)) / 2;
        //正确的点
        float rightX = x + correctDistance;
        float rightY = y + correctDistance;

        float nameTagToX;
        float nameTagToY;

        if (x < halfWidth) {
          nameTagToX = rightX + toX + dip2px(context, 60);
        } else {
          nameTagToX = rightX + toX - dip2px(context, 65);
        }
        nameTagToY = rightY + toY + (dip2px(context, 60) - dip2px(context, 20.5f)) / 2;

        View floatView;
//        View nameTagView;
        long delayTime;
        if (i == 1) {
          delayTime = 300;
          floatView = view1;
//          nameTagView = view5;
          floatView.setOnClickListener(v -> {
            Toast.makeText(context, "A", Toast.LENGTH_SHORT).show();
            closeMenu();
          });
        } else if (i == 2) {
          delayTime = 100;
          floatView = view2;
//          nameTagView = view6;
          floatView.setOnClickListener(v -> {
            Toast.makeText(context, "B", Toast.LENGTH_SHORT).show();
            closeMenu();
          });
        } else if (i == 3) {
          delayTime = 0;
          floatView = view3;
//          nameTagView = view7;
          floatView.setOnClickListener(v -> {
            Toast.makeText(context, "C", Toast.LENGTH_SHORT).show();
            closeMenu();
          });
        } else {
          delayTime = 200;
          floatView = view4;
//          nameTagView = view8;
          floatView.setOnClickListener(v -> {
            Toast.makeText(context, "D", Toast.LENGTH_SHORT).show();
            closeMenu();
          });
        }

        floatView.setX(rightX);
        floatView.setY(rightY);

//        nameTagView.setX(nameTagToX);
//        nameTagView.setY(nameTagToY);

        floatingDraggedView.addView(floatView, 1, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
//        floatingDraggedView.addView(nameTagView, 1, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

        AnimatorSet set = new AnimatorSet();

        ObjectAnimator animatorX = ObjectAnimator.ofFloat(floatView, "X", rightX, rightX + toX);
        animatorX.setInterpolator(new OvershootInterpolator());
        animatorX.setDuration(300);

        ObjectAnimator animatorY = ObjectAnimator.ofFloat(floatView, "Y", rightY, rightY + toY);
        animatorY.setInterpolator(new OvershootInterpolator());
        animatorY.setDuration(300);

//        ObjectAnimator animatorName = ObjectAnimator.ofFloat(nameTagView, "alpha", 0, 1);
//        animatorName.setDuration(300);

        set.setStartDelay(delayTime);
        set.play(animatorX).with(animatorY)/*.with(animatorName)*/;
        set.start();
      }
      postDelayed(closeRunnable, 3000);
    }

    /**
     * 更新位置
     */
    public void restorePosition() {
      // 读取保存的位置
      float x = sp.getFloat(KEY_FLOATING_X, -1);
      float y = sp.getFloat(KEY_FLOATING_Y, -1);
      if (x == -1 && y == -1) { // 初始位置
        x = getMeasuredWidth() - floatImageView.getMeasuredWidth();
        y = getMeasuredHeight() * 2 / 3;
      }

      floatImageView.layout((int) x, (int) y,
          (int) x + floatImageView.getMeasuredWidth(), (int) y + floatImageView.getMeasuredHeight());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
      super.onInterceptTouchEvent(ev);
      return dragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
      dragHelper.processTouchEvent(event);
      return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
      Log("dispatchTouchEvent");
      int action = event.getActionMasked();
      switch (action) {
        case MotionEvent.ACTION_DOWN:
          mLastX = event.getRawX();
          mLastY = event.getRawY();
          break;
        case MotionEvent.ACTION_MOVE:
          if (isTouchFloatBall(event)) {
            removeCallbacks(mFadeOutRunnable);
            setFloatImage(R.drawable.float_btn);
          }

          float x = event.getRawX();
          float y = event.getRawY();
          int deltaX = (int) (x - mLastX);
          int deltaY = (int) (y - mLastY);
          if (deltaX > 10 || deltaY > 10) {
            closeMenu();
          }
          break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
          postDelayed(mFadeOutRunnable, 3000);
          break;
        default:
          break;
      }
      return super.dispatchTouchEvent(event);
    }

    @Override
    public void computeScroll() {
      if (dragHelper.continueSettling(true)) {
        invalidate();
      }
    }

    /**
     * 是否摸到了某个view
     *
     * @param ev
     * @return
     */
    private boolean isTouchFloatBall(MotionEvent ev) {
      if (floatImageView != null && floatImageView.getVisibility() == VISIBLE) {
        Rect bounds = new Rect();
        floatImageView.getGlobalVisibleRect(bounds);
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        return bounds.contains(x, y);
      }
      return false;
    }

    private FadeOutRunnable mFadeOutRunnable = new FadeOutRunnable();

    private class FadeOutRunnable implements Runnable {

      @Override
      public void run() {
        if (!isMenuShow) {
          // 过一会换图片
          if (isOnLeft()) {
            setFloatImage(R.drawable.float_btn_left);
          } else {
            setFloatImage(R.drawable.float_btn_right);
          }
//                    setFloatImage(false);
        }
      }
    }

    private CloseRunnable closeRunnable = new CloseRunnable();

    private class CloseRunnable implements Runnable {

      @Override
      public void run() {
        if (isMenuShow) {
          closeMenu();
//                    setFloatImage(false);
        }
      }
    }

    public void setFloatImage(int res) {
      floatImageView.setImageResource(res);
      AnimationDrawable animationDrawable = (AnimationDrawable) floatImageView.getDrawable();
      animationDrawable.start();
    }

    private boolean isOnLeft() {
      int[] floatLocation = new int[2];
      floatImageView.getLocationOnScreen(floatLocation);
      return floatLocation[0] + floatImageView.getWidth() / 2 <= getMeasuredWidth() / 2;
    }

    private void Log(String msg) {
      Log.e("Tag", msg);
    }
  }

  private static class PositionObservable extends Observable {
    static PositionObservable sInstance;

    public static PositionObservable getInstance() {
      if (sInstance == null) {
        sInstance = new PositionObservable();
      }
      return sInstance;
    }

    /**
     * 通知观察者FloatingDragger
     */
    void update() {
      setChanged();
      notifyObservers();
    }
  }
}
